package user

import (
	"cgs-server/helper"
	"cgs-server/pkg/set"
	"cgs-server/server"
	"cgs-server/server/assets/cgs"
	"cgs-server/server/base"
	"cgs-server/server/model"
	"cgs-server/server/store/sms"
	"cgs-server/server/system/role"
	"cgs-server/server/system/user_role"
	"errors"
	"fmt"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"strings"
	"time"
)

type UserService interface {
	base.Service
	// 修改密码
	ChangePassword(mdl *model.DataUserModel) error
	// 重置密码
	ResetPassword(mdl *model.DataUserModel) error
	// 找回密码
	RetrievePassword(mdl *model.DataUserModel) error
	// 查询用户
	GetByUserIdOrUserName(mdl *model.DataUserModel) (*model.User, error)
	// 查询某个角色下的用户数
	CountByRoleId(roleId string) (int64, error)
	// 获取所有应用的所有权限
	GetAllVisualAuths(tenantId string) (map[string][]string, error)
	// 根据 tenantId 批量删除用户
	BatchRemoveUserByTenantId(tenantId string, user *model.User) error
	ListDept(duModel *model.DataUserModel, deptId string) (interface{}, error)
	// 根据用户名查找用户
	FindByUsername(mdl *model.DataUserModel) (*model.User, error)

	GetAppAuth(visualId string, user *model.User) ([]string, error)
	GetAppAuth2(visualId string, user *model.User) (*model.AppAuthVo, error)
}

func NewUserService() UserService {
	userRepo := NewUserRepository()
	return &userService{
		userRepo:     userRepo,
		userRoleRepo: user_role.NewUserRoleRepository(),
		ServiceImpl:  base.ServiceImpl{Repo: userRepo},
	}
}

type userService struct {
	userRepo     UserRepository
	userRoleRepo user_role.UserRoleRepository
	base.ServiceImpl
}

func (u *userService) GetAppAuth(visualId string, user *model.User) ([]string, error) {
	usr, err := u.GetByUserIdOrUserName(&model.DataUserModel{
		Data: user,
		User: user,
	})
	if err != nil {
		return nil, err
	}

	if usr.AppAuths == nil {
		return []string{}, nil
	}
	if strings, ok := usr.AppAuths[visualId]; ok {
		return strings, nil
	}
	return []string{}, nil
}

func (u *userService) GetAppAuth2(visualId string, user *model.User) (*model.AppAuthVo, error) {
	usr, err := u.GetByUserIdOrUserName(&model.DataUserModel{
		Data: user,
		User: user,
	})
	if err != nil {
		return nil, err
	}

	appAuth := make([]string, 0)
	if usr.AppAuths != nil {
		if strings, ok := usr.AppAuths[visualId]; ok {
			appAuth = strings
		}
	}

	var formAuth map[string][]string

	// formAuth
	if usr.FormAuths != nil {
		if fa, ok := usr.FormAuths[visualId]; ok {
			formAuth = fa
			// 这里把用户拥有的分发所有的表单权限去掉,需要判断表单权限类型
			if !user.IsFormAuthTypeDistributeAll(visualId) {
				appNewAuth := make([]string, 0)
				for _, s := range appAuth {
					if strings.Contains(s, "EDIT_FORM") {
						continue
					}
					appNewAuth = append(appNewAuth, s)
				}
				appAuth = appNewAuth
			}
		}
	}
	return &model.AppAuthVo{
		AppAuth:  appAuth,
		FormAuth: formAuth,
	}, nil
}

func (u *userService) Init(name ...string) error {
	err := u.userRepo.InitDB()
	if err != nil {
		return err
	}
	//err = u.userRoleRepo.InitDB()
	return err
}

func (u *userService) Save(mdl *model.DataUserModel) error {
	// username 用户名需要唯一，要与数据库对比
	if user, ok := mdl.Data.(*model.User); ok {

		// 根据用户名查询
		result, err := u.userRepo.FindByUsername(user.Username)
		if err != nil {
			return err
		}
		if result != nil {
			//return errors.New("Username is already exist.")
			return fmt.Errorf("Username '%s' is already exist.", result.Username)
		}
		// 添加基本用户信息
		salt := helper.TimeToString(time.Now(), "yyyyMMddHHmmss")
		password := helper.MD5(user.Password + salt)
		user.Pwd = password
		user.Salt = salt

		err = u.userRepo.Insert(mdl)
		if err != nil {
			return err
		}
		// 添加关联角色信息，2020-12-18 注释掉此代码
		/*if user.Roles != nil {
			err = u.userRoleRepo.UpdateByUserId(user)
			return err
		}*/
		return nil
	}

	//return u.userRepo.Insert(mdl)
	return errors.New("mdl.Data is not type of *model.User")
}

func (u *userService) ChangePassword(mdl *model.DataUserModel) error {
	if changeModel, ok := mdl.Data.(*model.ChangeUserPasswordModel); ok {
		if mdl.User == nil {
			return errors.New("The user is not existed.")
		}
		oldPassword := changeModel.OldPassword
		newPassword := changeModel.NewPassword

		oldPassword = helper.MD5(oldPassword + mdl.User.Salt)
		if oldPassword != mdl.User.Password {
			return errors.New("Old password is not correct.")
		}
		// change password
		salt := helper.TimeToString(time.Now(), "yyyyMMddHHmmss")
		password := helper.MD5(newPassword + salt)
		changeModel.Password = password
		changeModel.Salt = salt

		// 更新数据库
		return u.userRepo.ChangePassword(mdl)
	}
	return errors.New("model.DataUserModel.Data is not type of model.ChangeUserPasswordModel")
}

func (u *userService) Update(mdl *model.DataUserModel) error {
	if user, ok := mdl.Data.(*model.User); ok {
		// 需要查找完整的用户信息，包含角色名称，为 超级管理员 则不允许修改
		findUser, err := u.GetByUserIdOrUserName(mdl)
		if err != nil {
			return err
		}
		// 如果用户为空则直接更新
		if findUser.Role != nil {
			if findUser.IsSuperAdmin() {
				return errors.New("Super adminstrator is not allowed to update.")
			}
			if findUser.IsAdmin() && user.RoleID != findUser.Role.GetId() && findUser.Role.UserSize == 1 {
				// 是管理员，且只有这一个用户，此时不允许修改用户的管理员角色
				return errors.New("Not allowed to update the last administrator")
			}
		}
		// 更新用户基本信息
		err = u.userRepo.Update(mdl)
		if err != nil {
			return err
		}
		// 更新用户的角色信息
		// 2020-12-18 修改
		/*if user.Roles != nil {
			err = u.userRoleRepo.UpdateByUserId(user)
			return err
		}*/
		return err
	} else {
		return errors.New("user type error")
	}
}

func (u *userService) GetByUserIdOrUserName(mdl *model.DataUserModel) (*model.User, error) {
	userData, ok := mdl.Data.(*model.User)
	if !ok {
		return nil, errors.New("User type error.")
	}
	if userData.UserId.IsZero() && userData.Username == "" {
		return nil, errors.New("UserId or username is required.")
	}
	var user *model.User
	if !userData.UserId.IsZero() {
		res, err := u.userRepo.FindOne(mdl)
		if err != nil {
			return nil, err
		}
		user = res.(*model.User)
	} else if userData.Username != "" {
		res, err := u.userRepo.FindByUsername(userData.Username)
		if err != nil {
			return nil, err
		}
		user = res
	}
	if user == nil {
		return nil, errors.New("The user is not exist.")
	}

	// 根据 id 查询后台角色
	roleService := role.NewRoleService()
	err := roleService.Init()
	if err != nil {
		return nil, err
	}
	roleData := &model.Role{}
	roleData.SetTenantId(user.TenantId) // 这行代码不必加
	roleId, err := primitive.ObjectIDFromHex(user.RoleID)
	if err != nil {
		return nil, err
	}
	roleData.Id = roleId
	duModel := &model.DataUserModel{
		Data: roleData,
		User: mdl.User,
	}
	roleRes, _ := roleService.GetByRoleId(duModel)
	if roleRes == nil {
		return user, nil
	}
	user.Role = roleRes
	user.RoleName = roleRes.RoleAlias
	user.OperatingAuthorities = roleRes.Authorities

	if roleRes.RoleAlias == "Administrator" || roleRes.RoleAlias == "AppAdministrator" {
		// 如果是管理员或者应用管理员，则获取所有应用的所有权限
		appAuth, err := u.GetAllVisualAuths(mdl.User.GetTenantId())
		if err != nil {
			return nil, err
		}
		user.AppAuths = appAuth
	} else {
		// 查询用户拥有的应用角色
		userRoleList, err := u.userRoleRepo.FindByUserId(user.UserId)
		if err != nil {
			return nil, err
		}
		sliceRoleIds := make([]primitive.ObjectID, len(*userRoleList))
		for idx, ur := range *userRoleList {
			roleId, err := primitive.ObjectIDFromHex(ur.RoleId)
			if err != nil {
				return nil, err
			}
			sliceRoleIds[idx] = roleId
		}
		roleData = &model.Role{}
		roles, err := roleService.ListByIds(sliceRoleIds, duModel)
		if err != nil {
			return nil, err
		}
		if len(*roles) == 0 {
			return user, nil
		}
		// 处理重复的 应用 id
		if user.AppAuths == nil {
			user.AppAuths = make(map[string][]string, len(*roles))
		}
		if user.FormAuths == nil {
			user.FormAuths = make(map[string]map[string][]string)
		}
		if user.ProjVisualIdMap == nil {
			user.ProjVisualIdMap = make(map[string]string, len(*roles))
		}
		if user.SceneProjIdMap == nil {
			user.SceneProjIdMap = make(map[string]string, len(*roles))
		}

		cgsService := cgs.NewCgsService()

		appFormAuthSet := make(map[string]map[string]set.Set)

		for _, r := range *roles {
			// 查询一下 projectId
			cgsProj, _ := cgsService.GetByPublishId(r.VisualId, mdl.User)
			//if cgsProj == nil {
			//	continue
			//}
			if cgsProj != nil {
				user.ProjVisualIdMap[cgsProj.ID.Hex()] = r.VisualId
				sceneId, _ := cgsProj.GetSceneId()
				if sceneId != "" {
					user.SceneProjIdMap[sceneId] = cgsProj.ID.Hex()
				}
			}

			// 应用角色的权限
			if auths, ok := user.AppAuths[r.VisualId]; ok {
				for idx := range r.AppAuths {
					flag := false
					for i := range auths {
						if auths[i] == r.AppAuths[idx] {
							flag = true
							break
						}
					}
					if !flag {
						auths = append(auths, r.AppAuths[idx])
					}
				}
				user.AppAuths[r.VisualId] = auths
			} else {
				user.AppAuths[r.VisualId] = r.AppAuths
			}

			if appFormAuthSet[r.VisualId] == nil {
				appFormAuthSet[r.VisualId] = make(map[string]set.Set)
			}
			for s, strings := range r.FormAuths {
				var formAuthSet set.Set
				if appFormAuthSet[r.VisualId][s] == nil {
					appFormAuthSet[r.VisualId][s] = set.NewSet()
				}
				formAuthSet = appFormAuthSet[r.VisualId][s]
				for _, s2 := range strings {
					formAuthSet.Add(s2)
				}
			}

			//formAuth := make(map[string][]string)
			//formAuthSet := make(map[string]set.Set)
			//for s, strings := range r.FormAuths {
			//	if formAuthSet[s] == nil {
			//		formAuthSet[s] = set.NewSet()
			//	}
			//	for _, s2 := range strings {
			//		formAuthSet[s].Add(s2)
			//	}
			//}
			//for k, v := range formAuthSet {
			//	v.Each(func(a interface{}) bool {
			//		formAuth[k] = append(formAuth[k], a.(string))
			//		return false
			//	})
			//}
			//user.FormAuths[r.VisualId] = formAuth
		}
		for visualId, v := range appFormAuthSet {
			formAuth := make(map[string][]string)
			for formId, auths := range v {
				auths.Each(func(a interface{}) bool {
					formAuth[formId] = append(formAuth[formId], a.(string))
					return false
				})
			}
			user.FormAuths[visualId] = formAuth
		}
	}

	if user.AppAuths == nil {
		user.AppAuths = make(map[string][]string)
	}
	return user, nil
}

func (u *userService) List(mdl *model.DataUserModel) (interface{}, error) {
	result, err := u.userRepo.Find(mdl)
	return result, err
}
func (u *userService) ListDept(mdl *model.DataUserModel, deptId string) (interface{}, error) {
	result, err := u.userRepo.FindByDept(deptId)
	return result, err
}
func (u *userService) RemoveLogic(mdl *model.DataUserModel) error {
	// 逻辑删除用户，真实删除用户角色关联表
	if user, ok := mdl.Data.(*model.User); ok {
		// 判断id
		if user.UserId.IsZero() {
			return errors.New("UserId is required.")
		}
		// admin 用户不允许删除
		findUser, err := u.GetByUserIdOrUserName(mdl)
		if err != nil {
			return err
		}
		if findUser.Username == "admin" {
			return errors.New("It is not allowed to delete system built-in users.")
		}
		if findUser.IsSuperAdmin() {
			return errors.New("Super adminstrator is not allowed to delete.")
		}
		if findUser.IsAdmin() && user.RoleID != findUser.Role.GetId() && findUser.Role.UserSize == 1 {
			// 是管理员，且只有这一个用户，此时不允许修改用户的管理员角色
			return errors.New("Not allowed to delete the last administrator")
		}
		// 删除用户
		err = u.userRepo.DeleteLogic(mdl)
		if err != nil {
			return err
		}
		// 删除用户角色关联表
		err = u.userRoleRepo.DeleteByUserId(user.UserId.Hex())
		return nil
	} else {
		return errors.New("User type error.")
	}
}

func (u *userService) CountByRoleId(roleId string) (int64, error) {
	filter := bson.M{
		"RoleID": roleId,
	}
	return u.userRepo.Count(&model.DataUserModel{
		Filter: &filter,
	})
}

func (u *userService) GetAllVisualAuths(tenantId string) (map[string][]string, error) {
	// 集合名
	visualCollectionName := server.CgsPortalVisualCollectionName + "ThreeD"
	visualCollectionNameEarth := server.CgsPortalVisualCollectionName + "Earth"
	visualCollectionNameTwoD := server.CgsPortalVisualCollectionName + "TwoD"
	visualCollectionNameVisual := server.CgsPortalVisualCollectionName + "Visual"
	visualCollectionNameBim := server.CgsPortalVisualCollectionName + "Bim"
	visualCollectionNameWorkflow := server.CgsPortalVisualCollectionName + "Workflow"
	visualCollectionNameApp := server.CgsPortalVisualCollectionName + "App"

	// 查询 visual
	visualList, err := u.userRepo.FindByTenantId(visualCollectionName, tenantId)
	visualListEarth, err := u.userRepo.FindByTenantId(visualCollectionNameEarth, tenantId)
	visualListTwoD, err := u.userRepo.FindByTenantId(visualCollectionNameTwoD, tenantId)
	visualListVisual, err := u.userRepo.FindByTenantId(visualCollectionNameVisual, tenantId)
	visualListBim, err := u.userRepo.FindByTenantId(visualCollectionNameBim, tenantId)
	visualListWorkflow, err := u.userRepo.FindByTenantId(visualCollectionNameWorkflow, tenantId)
	visualListApp, err := u.userRepo.FindByTenantId(visualCollectionNameApp, tenantId)
	if err != nil {
		return nil, err
	}
	//if len(visualList) == 0 && len(visualListEarth) == 0 && len(visualListTwoD) == 0 && len(visualListVisual) == 0 && len(visualListBim) == 0 && len(visualListWorkflow) == 0 {
	//	return nil, nil
	//}
	appAuths := server.GetAllAppAuth()
	auths := []string{string(server.ManageAppAuth)}
	for i := range appAuths {
		auths = append(auths, appAuths[i].Name)
	}
	appAuth := make(map[string][]string)
	for i := range visualList {
		appAuth[visualList[i].ID.Hex()] = auths
	}
	for i := range visualListEarth {
		appAuth[visualListEarth[i].ID.Hex()] = auths
	}
	for i := range visualListTwoD {
		appAuth[visualListTwoD[i].ID.Hex()] = auths
	}
	for i := range visualListVisual {
		appAuth[visualListVisual[i].ID.Hex()] = auths
	}
	for i := range visualListBim {
		appAuth[visualListBim[i].ID.Hex()] = auths
	}
	for i := range visualListWorkflow {
		appAuth[visualListWorkflow[i].ID.Hex()] = auths
	}
	for i := range visualListApp {
		appAuth[visualListApp[i].ID.Hex()] = auths
	}
	return appAuth, nil
}

func (u *userService) BatchRemoveUserByTenantId(tenantId string, user *model.User) error {
	userModel := &model.User{}
	userModel.TenantId = tenantId
	err := u.userRepo.BatchDeleteLogic(&model.DataUserModel{
		Data: userModel,
		User: user,
		Filter: &bson.M{
			"tenantId": tenantId,
		},
	})
	return err
}

func (u *userService) ResetPassword(mdl *model.DataUserModel) error {
	if changeModel, ok := mdl.Data.(*model.ChangeUserPasswordModel); ok {
		if mdl.User == nil {
			return errors.New("The user is not existed.")
		}
		if !mdl.User.IsAdmin() {
			return errors.New("Permission denied.")
		}
		newPassword := changeModel.NewPassword
		// change password
		salt := helper.TimeToString(time.Now(), "yyyyMMddHHmmss")
		password := helper.MD5(newPassword + salt)
		changeModel.Password = password
		changeModel.Salt = salt

		// 更新数据库
		return u.userRepo.ChangePassword(mdl)
	} else {
		return model.NewTypeError("user")
	}
}

func (u *userService) RetrievePassword(mdl *model.DataUserModel) error {
	// 1. 校验验证码
	changeModel := mdl.Data.(*model.ChangeUserPasswordModel)
	smsCode, _ := sms.GetSmsCode(changeModel.PhoneNumber)
	if smsCode == nil || smsCode.IsExpired() {
		return errors.New("验证码已过期，请重新发送。")
	}

	if smsCode.Code != changeModel.ValidationCode {
		return errors.New("验证码不正确。")
	}

	// 查询用户是否存在
	res, _ := u.userRepo.FindByUsername(changeModel.PhoneNumber)
	if res == nil {
		return errors.New("用户不存在。")
	}

	changeModel.UserId = res.UserId

	// 重置密码
	newPassword := changeModel.NewPassword
	// change password
	salt := helper.TimeToString(time.Now(), "yyyyMMddHHmmss")
	password := helper.MD5(newPassword + salt)
	changeModel.Password = password
	changeModel.Salt = salt

	// 更新数据库
	return u.userRepo.ChangePassword(mdl)
}

func (u *userService) FindByUsername(mdl *model.DataUserModel) (*model.User, error) {
	userData, ok := mdl.Data.(*model.User)
	if !ok {
		return nil, errors.New("User type error.")
	}
	return u.userRepo.FindByUsername(userData.Username)
}
